﻿#include "widget.h"

#include <iostream>
#include <windows.h>
#include <tlhelp32.h>	//进程快照函数头文件
#include <string>
#include <stdio.h>
#include <tchar.h>
#include <Psapi.h>
#pragma comment (lib,"Psapi.lib")
using namespace std;

#ifdef UNICODE

#define QStringToTCHAR(x)     (wchar_t*) x.utf16()
#define PQStringToTCHAR(x)    (wchar_t*) x->utf16()
#define TCHARToQString(x)     QString::fromUtf16((x))
#define TCHARToQStringN(x,y)  QString::fromUtf16((x),(y))

#else

#define QStringToTCHAR(x)     x.local8Bit().constData()
#define PQStringToTCHAR(x)    x->local8Bit().constData()
#define TCHARToQString(x)     QString::fromLocal8Bit((x))
#define TCHARToQStringN(x,y)  QString::fromLocal8Bit((x),(y))

#endif

BOOL DosPathToNtPath(LPTSTR pszDosPath, LPTSTR pszNtPath)
{
    TCHAR			szDriveStr[500];
    TCHAR			szDrive[3];
    TCHAR			szDevName[100];
    INT				cchDevName;
    INT				i;

    //检查参数
    if (!pszDosPath || !pszNtPath)
        return FALSE;

    //获取本地磁盘字符串
    if (GetLogicalDriveStrings(sizeof(szDriveStr), szDriveStr))
    {
        for (i = 0; szDriveStr[i]; i += 4)
        {
            if (!wcscmp(&(szDriveStr[i]), (L"A:\\")) || !wcscmp(&(szDriveStr[i]), _T(L"B:\\")))
                continue;

            szDrive[0] = szDriveStr[i];
            szDrive[1] = szDriveStr[i + 1];
            szDrive[2] = '\0';
            if (!QueryDosDevice(szDrive, szDevName, 100))//查询 Dos 设备名
                return FALSE;

            cchDevName = lstrlen(szDevName);
            if ((pszDosPath, szDevName, cchDevName) == 0)//命中
            {
                lstrcpy(pszNtPath, szDrive);//复制驱动器
                lstrcat(pszNtPath, pszDosPath + cchDevName);//复制路径

                return TRUE;
            }
        }
    }

    lstrcpy(pszNtPath, pszDosPath);

    return FALSE;
}

//获取进程完整路径
BOOL GetProcessFullPath(DWORD dwPID, TCHAR pszFullPath[MAX_PATH], __out QString& str)
{
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
    if (!hProcess)
    {
        //QMessageBox::warning(NULL,"GetPathByProcessID","无权访问该进程");
        str = "";
    }
    WCHAR filePath[MAX_PATH];
    DWORD ret= GetModuleFileNameEx(hProcess, NULL, filePath, MAX_PATH) ;
    QString file = QString::fromStdWString( filePath );
    //QMessageBox::warning(NULL,"GetPathByProcessID ret=", QString::number(ret)+":"+file);
    CloseHandle(hProcess);
    str = ret == 0 ? "" : file;

    return true;
}

string GetProcessInfo(__in HANDLE hProcess, __in WCHAR* processName)
{
    PROCESSENTRY32* pinfo = new PROCESSENTRY32; //进程信息 （pinfo->dwSize = sizeof(PROCESSENTRY32);）
    MODULEENTRY32* minfo = new MODULEENTRY32; //模块信息 （minfo->dwSize = sizeof(MODULEENTRY32);）
    char shortpath[MAX_PATH];				//保存路径变量

    int flag = Process32First(hProcess, pinfo);	// 从第一个进程开始
    while (flag) {

        if (wcscmp(pinfo->szExeFile, processName) == 0) {

            // 创建进程快照
            HANDLE hModule = CreateToolhelp32Snapshot(
                        TH32CS_SNAPMODULE,		//（DWORD） 快照返回的对象，TH32CS_SNAPMODULE 是指 "特定进程的使用模块的列表"
                        pinfo->th32ProcessID	//（DWORD） 要获取快照进程的PID，当前进程/系统列表 快照时设为0
                        );

            // 把第一个模块信息给 minfo
            Module32First(
                        hModule,  //（HANDLE） CreateToolhelp32Snapshot 的返回句柄
                        minfo	 // （LPMODULEENTRY32）  接收模块信息
                        );

            // 把文件路径给 shortpath
            GetShortPathName(
                        minfo->szExePath,	//  文件路径（但最好不要用这个，因为这个碰到中文会出现乱码）
                        (LPWSTR)shortpath,		// 用来接收 minfo->szExePath 兼容中文的值
                        256			// 缓冲区大小
                        );

            return shortpath;
        }

        // 下一个进程
        flag = Process32Next(hProcess, pinfo);
    }

    return NULL;
}

int Widget::getAllProcess()
{
    int countProcess = 0;	//当前进程数量计数变量
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // 创建进程快照
    PROCESSENTRY32W currentProcess;	// 用来接收 hProcessSnap 的信息

    currentProcess.dwSize = sizeof(currentProcess);		//在使用这个结构之前，先设置它的大小
    HANDLE hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);//给系统内的所有进程拍一个快照

    if (hProcess == INVALID_HANDLE_VALUE)
    {
        printf("CreateToolhelp32Snapshot()调用失败!\n");
        return -1;
    }

    bool bMore = Process32First(hProcessSnap, &currentProcess);	//获取第一个进程信息
    while (bMore) {
        QString str;
        TCHAR szProcessName[MAX_PATH] = { 0 };
        GetProcessFullPath(currentProcess.th32ProcessID, szProcessName, str);
        m_ProList.append(str);
        bMore = Process32Next(hProcessSnap, &currentProcess);	//遍历下一个
        countProcess++;
    }

    CloseHandle(hProcess);	//清除hProcess句柄

    // QMessageBox::information(this,QString::fromLocal8Bit("检测完毕"),QString::fromLocal8Bit("共有以上%1个进程在运行\n").arg(countProcess), QMessageBox::Ok);
}

// 获取文件图标
HICON fileIcon(std::string extention)
{
    HICON icon = NULL;
    if (extention.length() > 0)
    {
        LPCSTR name = extention.c_str();

        SHFILEINFOA info;
        if (SHGetFileInfoA(name,
                           FILE_ATTRIBUTE_NORMAL,
                           &info,
                           sizeof(info),
                           SHGFI_SYSICONINDEX | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES))
        {
            icon = info.hIcon;
        }
    }

    return icon;
}

HICON QueryExeIcon(LPCTSTR lpszExePath)
{
    HICON hIcon = NULL;
    SHFILEINFO FileInfo;
    DWORD_PTR dwRet = ::SHGetFileInfo(lpszExePath, 0, &FileInfo, sizeof(SHFILEINFO), SHGFI_ICON);

    // 目标文件不存在
    if (dwRet)
    {
        hIcon = FileInfo.hIcon;
    }
    return hIcon;
}
// 获取文件类型
std::string fileType(std::string extention)
{
    std::string type = "";
    if (extention.length() > 0)
    {
        LPCSTR name = extention.c_str();

        SHFILEINFOA info;
        if (SHGetFileInfoA(name,
                           FILE_ATTRIBUTE_NORMAL,
                           &info,
                           sizeof(info),
                           SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES))
        {
            type = info.szTypeName;
        }
    }

    return type;
}

// 获取文件夹图标
HICON folderIcon()
{
    std::string str = "folder";
    LPCSTR name = str.c_str();

    HICON icon = NULL;

    SHFILEINFOA info;
    if (SHGetFileInfoA(name,
                       FILE_ATTRIBUTE_DIRECTORY,
                       &info,
                       sizeof(info),
                       SHGFI_SYSICONINDEX | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES))
    {
        icon = info.hIcon;
    }

    return icon;
}

// 获取文件夹类型
std::string folderType()
{
    std::string str = "folder";
    LPCSTR name = str.c_str();

    std::string type;

    SHFILEINFOA info;
    if (SHGetFileInfoA(name,
                       FILE_ATTRIBUTE_DIRECTORY,
                       &info,
                       sizeof(info),
                       SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES))
    {
        type = info.szTypeName;
    }

    return type;
}

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    setGeometry(200, 200, 800, 800);
    setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);

    m_Hbox = new QHBoxLayout(this);

    m_ExtListWidget = new QListWidget;
    m_ExtListWidget->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Preferred);

    m_ProListWidget = new QListWidget;
    m_ProListWidget->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);

    m_Hbox->addWidget(m_ExtListWidget);
    m_Hbox->addWidget(m_ProListWidget);

    m_Hbox->setStretch(0,3);
    m_Hbox->setStretch(1,7);

    getExtIcon();
    getProIcon();
}


Widget::~Widget()
{
}

void Widget::getExtIcon()
{

    m_ExtListWidget->setViewMode(QListView::ListMode);

    std::string strArray[13] = {"folder", ".exe", ".zip", ".har", ".hwl", ".accdb",
                                ".xlsx", ".pptx", ".docx", ".txt", ".h", ".cpp", ".pro"};
    int nCount = sizeof(strArray) / sizeof(std::string);
    for (int i = 0; i < nCount ; ++i)
    {
        // 获取图标、类型
        QPixmap pixmap;
        std::string type;
        int nPos = -1;
        nPos = strArray[i].find(".");
        if (nPos >= 0)
        {
            // Qt4：QPixmap::fromWinHICON(icon)
            pixmap = QtWin::fromHICON(fileIcon(strArray[i]));
            type = fileType(strArray[i]);
        }
        else
        {
            pixmap = QtWin::fromHICON(folderIcon());
            type = folderType();
        }

        QIcon icon;
        icon.addPixmap(pixmap);
        QString strType = QString::fromLocal8Bit(type.c_str());

        // 添加单元项
        QListWidgetItem *pItem = new QListWidgetItem;
        pItem->setIcon(icon);
        pItem->setText(strType);
        m_ExtListWidget->addItem(pItem);
    }
}

void Widget::getProIcon()
{
    getAllProcess();

    QSet<QString> SetList;
    for(auto it : m_ProList)
    {
        SetList.insert(it);
    }

    int nCount = SetList.size();
    foreach(const QString& value, SetList)
    {
        if(value.isEmpty())
        {
            continue;
        }

        // 获取图标、类型
        QPixmap pixmap;
        std::string type;

        // Qt4：QPixmap::fromWinHICON(icon)
        pixmap = QtWin::fromHICON(QueryExeIcon(value.toStdWString().c_str()));
        type = fileType(value.toStdString());

        QIcon icon;
        icon.addPixmap(pixmap);
        QString strType = value;

        // 添加单元项
        QListWidgetItem *pItem = new QListWidgetItem;
        pItem->setCheckState(Qt::Unchecked);
        pItem->setIcon(icon);
        pItem->setText(strType);
        m_ProListWidget->addItem(pItem);
    }
}

